/*******************************************************************************
**                                                                            **
** Copyright (C)    (2016)                                               **
**                                                                            **
** All rights reserved.                                                       **
**                                                                            **
** This document contains proprietary information belonging to .         **
** Passing on and copying of this document, and communication                 **
** of its contents is not permitted without prior written authorization.      **
**                                                                            **
********************************************************************************
**                                                                            **
**  FILENAME    : Xcp.c                                                       **
**                                                                            **
**  Created on  :                                                             **
**  Author      : qinchun.yang                                                **
**  Vendor      :                                                             **
**  DESCRIPTION : Implementation for XCP	                                  **
**                                                                            **
**  SPECIFICATION(S) :   AUTOSAR classic Platform 4.2.2                       **
**                                                                            **
*******************************************************************************/

/*=======[V E R S I O N  I N F O R M A T I O N]===============================*/
#define XCP_VENDOR_ID 		(uint16)62
#define XCP_MODULE_ID  		(uint16)212

#define XCP_C_AR_MAJOR_VERSION  4u
#define XCP_C_AR_MINOR_VERSION  2u
#define XCP_C_AR_PATCH_VERSION  2u
#define XCP_C_SW_MAJOR_VERSION  1u
#define XCP_C_SW_MINOR_VERSION  0u
#define XCP_C_SW_PATCH_VERSION  0u

#include "Xcp_Internal.h"

#if (XCP_DEV_ERROR_DETECT == STD_ON)
#include "Det.h"
#endif
#include "Dem.h"

/*=======[V E R S I O N  C H E C K]===========================================*/
#if (XCP_C_AR_MAJOR_VERSION != XCP_H_AR_MAJOR_VERSION)
  #error "Xcp.c : Mismatch in Specification Major Version"
#endif
#if (XCP_C_AR_MINOR_VERSION != XCP_H_AR_MINOR_VERSION)
  #error "Xcp.c : Mismatch in Specification Major Version"
#endif
#if (XCP_C_AR_PATCH_VERSION != XCP_H_AR_PATCH_VERSION)
  #error "Xcp.c : Mismatch in Specification Major Version"
#endif
#if (XCP_C_SW_MAJOR_VERSION != XCP_H_SW_MAJOR_VERSION)
  #error "Xcp.c : Mismatch in Specification Major Version"
#endif
#if (XCP_C_SW_MINOR_VERSION != XCP_H_SW_MINOR_VERSION)
  #error "Xcp.c : Mismatch in Specification Major Version"
#endif
#if (XCP_C_SW_PATCH_VERSION != XCP_H_SW_PATCH_VERSION)
  #error "Xcp.c : Mismatch in Specification Major Version"
#endif




/*=======[E X T E R N A L   D A T A]==========================================*/
#define XCP_START_SEC_VAR_INIT_UNSPECIFIED
#include "XCP_MemMap.h"
VAR(Xcp_StatusType, XCP_VAR_INIT_UNSPECIFIED)Xcp_Status = XCP_UINIT;
VAR(Xcp_CommandStatusType, XCP_VAR_INIT_UNSPECIFIED) Xcp_CommandStatus = XCP_CMD_IDLE;
#define XCP_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "XCP_MemMap.h"

#define XCP_START_SEC_VAR_CLEARED_UNSPECIFIED
#include "XCP_MemMap.h"
#if ((XCP_MASTER_BLOCK_MODE == STD_ON)||(XCP_SLAVE_BLOCK_MODE == STD_ON))
VAR(Xcp_BlockBufIndxType, XCP_VAR) Xcp_BlockBufferPos = 0u;
VAR(Xcp_BlockBufIndxType, XCP_VAR) Xcp_BlockBufferLen = 0u;
#endif /* (XCP_MASTER_BLOCK_MODE == STD_ON)||(XCP_SLAVE_BLOCK_MODE == STD_ON) */
#define XCP_STOP_SEC_VAR_CLEARED_UNSPECIFIED
#include "XCP_MemMap.h"

#define XCP_START_SEC_VAR_CLEARED_UNSPECIFIED
#include "XCP_MemMap.h"
VAR(PduLengthType, XCP_VAR_CLEARED_UNSPECIFIED) Xcp_CmdLength;
VAR(PduLengthType, XCP_VAR_CLEARED_UNSPECIFIED) Xcp_RespLength;
VAR(PduLengthType, XCP_VAR_CLEARED_UNSPECIFIED) Xcp_EvLength;
#define XCP_STOP_SEC_VAR_CLEARED_UNSPECIFIED
#include "XCP_MemMap.h"

#define XCP_START_SEC_VAR_INIT_8
#include "XCP_MemMap.h"
VAR(uint8, XCP_VAR_INIT_8) Xcp_ProtectionStatus = XCP_PROTECTION;
VAR(uint8, XCP_VAR_INIT_8) Xcp_SessionStatus = 0u;
VAR(uint8, XCP_VAR_INIT_8)  Xcp_SendStatus = 0u;
#define XCP_STOP_SEC_VAR_INIT_8
#include "XCP_MemMap.h"

#define XCP_START_SEC_VAR_CLEARED_8
#include "XCP_MemMap.h"
VAR(uint8, XCP_VAR) Xcp_TransferTimeOutCnt;
#define XCP_STOP_SEC_VAR_CLEARED_8
#include "XCP_MemMap.h"

#define XCP_START_SEC_VAR_CLEARED_32
#include "XCP_MemMap.h"
#if ((XCP_GET_ID == STD_ON) || (XCP_GET_DAQ_EVENT_INFO == STD_ON) || (XCP_GET_SECTOR_INFO == STD_ON))
VAR(uint32, XCP_VAR) Xcp_UploadInfoLen;
#endif
#define XCP_STOP_SEC_VAR_CLEARED_32
#include "XCP_MemMap.h"

P2CONST(Xcp_ConfigType, XCP_VAR_CLEARED_32, XCP_APPL_DATA) Xcp_GlobalCfgPtr = NULL_PTR;

/*=======[I N T E R N A L   D A T A]==========================================*/
#define XCP_START_SEC_VAR_INIT_UNSPECIFIED
#include "XCP_MemMap.h"
static VAR(PduLengthType, XCP_VAR) Xcp_ServLength = 0u;
#define XCP_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "XCP_MemMap.h"



/*=======[I N T E R N A L   F U N C T I O N   D E C L A R A T I O N S]========*/
#define XCP_START_SEC_CODE
#include "XCP_MemMap.h"
static FUNC(void, XCP_CODE) Xcp_PendingTaskHandle(void);
static FUNC(void, XCP_CODE) Xcp_GenericCommandHandle(void);
static FUNC(void, XCP_CODE) Xcp_RxIndication
#if (XCP_PID_OFF_SUPPORT  == STD_ON)
(const PduIdType pduId,const PduLengthType len, P2CONST(uint8, AUTOMATIC, XCP_APPL_DATA) dataPtr);
#else
(const PduLengthType len, P2CONST(uint8, AUTOMATIC, XCP_APPL_DATA) dataPtr);
#endif

static FUNC(void, XCP_CODE) Xcp_RxCommandHal
#if (XCP_MASTER_BLOCK_MODE == STD_ON)
    (const uint8 pid, const PduLengthType len, P2CONST(uint8, AUTOMATIC, XCP_APPL_DATA) dataPtr);
#else
    (const PduLengthType len, P2CONST(uint8, AUTOMATIC, XCP_APPL_DATA) dataPtr);
#endif

static FUNC(void, XCP_CODE) Xcp_TxConfirmation(const PduIdType pduId);
static FUNC(void, XCP_CODE) Xcp_TxQueueHandler(void);

#if (XCP_MASTER_BLOCK_MODE == STD_ON)
static FUNC(void, XCP_CODE) Xcp_RxBlockHal
    (const uint8 pid, const PduLengthType len, P2CONST(uint8, AUTOMATIC, XCP_APPL_DATA) dataPtr);
#endif
static FUNC(void, XCP_CODE) Xcp_SendServ(void);
static FUNC(void, XCP_CODE) Xcp_RxCommandHal
#if (XCP_MASTER_BLOCK_MODE == STD_ON)
    (const uint8 pid, const PduLengthType len, P2CONST(uint8, AUTOMATIC, XCP_APPL_DATA) dataPtr);
#else
    (const PduLengthType len, P2CONST(uint8, AUTOMATIC, XCP_APPL_DATA) dataPtr);
#endif
#define XCP_STOP_SEC_CODE
#include "XCP_MemMap.h"

/*=======[F U N C T I O N   I M P L E M E N T A T I O N S]====================*/

#define XCP_START_SEC_CODE
#include "XCP_MemMap.h"

/******************************************************************************/
/*
 * @brief               <Xcp Module Initialization Function>
 * 
 * <This service initializes interfaces and variables of the AUTOSAR XCP layer> .
 * Service ID   :       <XCP_INIT_ID (0x00)>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <Xcp_ConfigPtr (IN)>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>    
 */
/******************************************************************************/
FUNC(void, XCP_CODE)
Xcp_Init(CONSTP2CONST(Xcp_ConfigType, AUTOMATIC, XCP_APPL_CONST) Xcp_ConfigPtr)
{
	Xcp_Status = XCP_UINIT;
	#if (XCP_DEV_ERROR_DETECT == STD_ON)
	if (NULL_PTR == Xcp_ConfigPtr)
	{
		Det_ReportError(XCP_MODULE_ID, XCP_INSTANCE_ID, XCP_SERVICE_ID_INIT, XCP_E_INV_POINTER);
	}
	else
	#endif /* (XCP_DEV_ERROR_DETECT == STD_ON) */
	{
		Xcp_GlobalCfgPtr = Xcp_ConfigPtr;
		/* clear the stack status */
		Xcp_ClearStatus();
        /* Clear Command Processor Common Status */
		Xcp_CommandInit();
		#if (XCP_PL_PGM == (XCP_PL_PGM & XCP_RESOURCE))
		Xcp_ProgramInit();
		#endif /* (XCP_PL_PGM == (XCP_PL_PGM & XCP_RESOURCE) */
		#if (XCP_BUILD_CHECKSUM == STD_ON)
		Xcp_InitCrc16CcittTable();	
		#endif
		#if (XCP_PL_CAL == (XCP_PL_CAL & XCP_RESOURCE))
		/* reset the MTA address, CAL_page Address and copy RP to WP */
		if (E_NOT_OK == Xcp_CALInit())
		{
			Dem_ReportErrorStatus(XCP_E_NOT_INITIALIZED, DEM_EVENT_STATUS_FAILED);
		}
		else
		#endif /* (XCP_PL_CAL == (XCP_PL_CAL & XCP_RESOURCE)) */

		#if (XCP_PL_DAQ == (XCP_PL_DAQ & XCP_RESOURCE))
		if (E_NOT_OK == Xcp_DAQInit())
		{
			Dem_ReportErrorStatus(XCP_E_NOT_INITIALIZED, DEM_EVENT_STATUS_FAILED);
		}
		else
		#endif /* (XCP_PL_DAQ == (XCP_PL_DAQ & XCP_RESOURCE)) */
		{
			Xcp_Status = XCP_DISCONNECT;
		}
	}
	return;
}

FUNC(void,XCP_CODE)
Xcp_MainFunction(void)
{
    /* In case something is in transmission */
    if (0x00 != (Xcp_SendStatus & XCP_SEND_PENDING))
    {
        Xcp_TransferTimeOutCnt++;
        if (Xcp_TransferTimeOutCnt >= XCP_TANSFER_TIME_OUT)
        {
            Xcp_SendStatus &= (uint8)(~XCP_SEND_PENDING);
            if (0x00 != ((XCP_CMD_TRANSF|XCP_CMD_BLOCK_TRANSF)&Xcp_CommandStatus) )
            {
                Xcp_CommandInit();
            }
            Xcp_TransferTimeOutCnt = 0x00u;
        }
    }
    /* In case last send request is denied. Restart the tx queue in the main function */
    else if (0x00 != (Xcp_SendStatus & XCP_SEND_REQUEST))
    {
        Xcp_TxQueueHandler();
    }
    else
    {
        /* Do Nothing */
    }
    /* Handle the pending task. */
    Xcp_PendingTaskHandle();
    /* One Command has been recieved successfully */
    if (XCP_CMD_RECV == Xcp_CommandStatus)
    {
        Xcp_CommandStatus = XCP_CMD_EXCUTE;
        Xcp_GenericCommandHandle();
    }
    return;
}

#if (XCP_VERSION_INFO_API == STD_ON)
FUNC(void, XCP_CODE)
Xcp_GetVersionInfo(P2VAR(Std_VersionInfoType, AUTOMATIC,XCP_APPL_DATA)versioninfo)
{
    Std_VersionInfoType  Xcp_VersionInfo =
    {
        XCP_VENDOR_ID,
        XCP_MODULE_ID,
        XCP_INSTANCE_ID,
        XCP_C_SW_MAJOR_VERSION,
        XCP_C_SW_MINOR_VERSION,
        XCP_C_SW_PATCH_VERSION
    };
    #if (XCP_DEV_ERROR_DETECT == STD_ON)
    if (NULL_PTR == versioninfo)
    {
    	Det_ReportError(XCP_MODULE_ID, XCP_INSTANCE_ID, XCP_SERVICE_ID_GET_VERSION_INFO, XCP_E_INV_POINTER);
    }
    else
    #endif /* (XCP_DEV_ERROR_DETECT == STD_ON) */
    {
        versioninfo->moduleID = Xcp_VersionInfo.moduleID;
        versioninfo->vendorID = Xcp_VersionInfo.vendorID;
        versioninfo->instanceID = Xcp_VersionInfo.instanceID;
        versioninfo->sw_major_version = Xcp_VersionInfo.sw_major_version;
        versioninfo->sw_minor_version = Xcp_VersionInfo.sw_minor_version;
        versioninfo->sw_patch_version = Xcp_VersionInfo.sw_patch_version;
    }
    return;

}
#endif

#if (XCP_SUPPRESS_TX_SUPPORTED == STD_ON)
FUNC(void, XCP_CODE)
Xcp_SetTransmissionMode(NetworkHandleType Channel, Xcp_TransmissionModeType Mode)
{
	/* Not support now */
}
#endif

FUNC(void, XCP_CODE) Xcp_ClearStatus(void)
{
    Xcp_ProtectionStatus = XCP_PROTECTION;
    Xcp_SessionStatus = 0;
    Xcp_SendStatus = XCP_SEND_IDLE;
    Xcp_TransferTimeOutCnt = 0;

    Xcp_CmdLength = 0;
    Xcp_RespLength = 0;
    Xcp_EvLength = 0;
    Xcp_ServLength = 0;

    #if (XCP_SEED_AND_UNLOCK == STD_ON)
    Xcp_SeedandKeyStatus = XCP_PRE_SEED;
    Xcp_SeedandKeyRes = 0u;
    #endif

    #if ((XCP_GET_ID == STD_ON)\
    || (XCP_GET_DAQ_EVENT_INFO == STD_ON)\
    || (XCP_GET_SECTOR_INFO == STD_ON))
    Xcp_UploadInfoLen = 0;
    #endif

    return;
}

/******************************************************************************/
/*
 * @brief               <Xcp Module Command Processor State Machine Init. Function>
 *
 * <Initialize command processor state machine and block buffer,
 * this function used in Xcp_Init,Xcp_Sync and Xcp_MainFunction(in case tx timeout)>.
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
FUNC(void, XCP_CODE) Xcp_CommandInit(void)
{
    Xcp_CommandStatus = XCP_CMD_IDLE;
    #if ((XCP_MASTER_BLOCK_MODE == STD_ON)||(XCP_SLAVE_BLOCK_MODE == STD_ON))
    Xcp_BlockBufferPos = 0;
    Xcp_BlockBufferLen = 0;
    #endif /* (XCP_MASTER_BLOCK_MODE == STD_ON)||(XCP_SLAVE_BLOCK_MODE == STD_ON) */
	#if (XCP_SET_REQUEST == STD_ON)
    Xcp_storeBufPos = XCP_STORE_DAQ_CFG_OFFSET;
	#endif
    if ((XCP_PRE_CONNECT == Xcp_Status)
    || (XCP_PRE_USERDEFINE == Xcp_Status))
    {
        Xcp_Status = XCP_DISCONNECT;
    }
    return;
}

static FUNC(void, XCP_CODE)
Xcp_PendingTaskHandle(void)
{
    #if (XCP_PL_PGM == (XCP_PL_PGM & XCP_RESOURCE))
    Xcp_PgmPendingTask();
    #endif
    return;
}

static FUNC(void, XCP_CODE)
Xcp_GenericCommandHandle(void)
{
    uint8 u1CommandCode = Xcp_CmdBuffer[XCP_PID_OFFSET];

    /* initialize the PID of RESP frame */
    Xcp_RespBuffer[XCP_PID_OFFSET] = XCP_RESP_POS_PID;
    Xcp_RespLength = 0x01;

    /* in non-CONNECT status only treat Connect & get_slave_id*/
    if (XCP_CMD_CONNECT == u1CommandCode)
    {
        Xcp_Connect();
    }
    else if ((XCP_CMD_TRANSPORT_LAYER_CMD == u1CommandCode)
    && (XCP_CMD_TL_GET_SLAVE_ID == Xcp_CmdBuffer[XCP_CMD_TL_SUB_CODE_OFFSET]))
    {
        #if (XCP_GET_SLAVE_ID == STD_ON)
        Xcp_GetSlaveId();
        #endif
    }
    /* other command shall be ignored when status is not connect */
    else if (XCP_CONNECT == Xcp_Status)
    {
        switch(u1CommandCode)
        {
            case XCP_CMD_DISCONNECT:
            {
                Xcp_Disconnect();
                break;
            }
            case XCP_CMD_GET_STATUS:
            {
                Xcp_GetStatus();
                break;
            }
            case XCP_CMD_SYNCH:
            {
                Xcp_Synch();
                break;
            }
            #if (XCP_GET_COMM_MODE_INFO == STD_ON)
            case XCP_CMD_GET_COMM_MODE_INFO:
            {
                Xcp_GetCommModeInfo();
                break;
            }
            #endif
            #if (XCP_GET_ID == STD_ON)
            case XCP_CMD_GET_ID:
            {
                Xcp_GetId();
                break;
            }
            #endif
            #if (XCP_SET_REQUEST == STD_ON)
            case XCP_CMD_SET_REQUEST:
            {
                Xcp_SetRequest();
                break;
            }
            #endif
            #if (XCP_SEED_AND_UNLOCK == STD_ON)
            case XCP_CMD_GET_SEED:
            {
                Xcp_GetSeed();
                break;
            }
            case XCP_CMD_UNLOCK:
            {
                Xcp_Unlock();
                break;
            }
            #endif
            #if (XCP_SET_MTA == STD_ON)
            case XCP_CMD_SET_MTA:
            {
                Xcp_SetMta();
                break;
            }
            #endif
            #if (XCP_UPLOAD == STD_ON)
            case XCP_CMD_UPLOAD:
            {
                Xcp_Upload();
                break;
            }
            #endif
            #if (XCP_SHORT_UPLOAD == STD_ON)
            case XCP_CMD_SHORT_UPLOAD:
            {
                Xcp_ShortUpload();
                break;
            }
            #endif
            #if (XCP_BUILD_CHECKSUM == STD_ON)
            case XCP_CMD_BUILD_CHECKSUM:
            {
                Xcp_BuildChecksum();
                break;
            }
            #endif
            #if (XCP_TRANSPORT_LAYER_CMD == STD_ON)
            case XCP_CMD_TRANSPORT_LAYER_CMD:
            {
                #if (XCP_PL_DAQ == (XCP_RESOURCE & XCP_PL_DAQ))
                #if (XCP_GET_DAQ_ID == STD_ON)
                if (XCP_CMD_TL_GET_DAQ_ID == Xcp_CmdBuffer[XCP_CMD_TL_SUB_CODE_OFFSET])
                {
                    Xcp_GetDaqId();
                }
                else
                #endif
                #endif
                {
                    Xcp_SetErrorCode(XCP_ERR_CMD_UNKNOWN);
                    Xcp_RespLength = 0x02u;
                    Xcp_SendResp();
                }
                break;
            }
            #endif

            /* CAL */
            #if (XCP_PL_CAL == (XCP_PL_CAL & XCP_RESOURCE))
            case XCP_CMD_DOWNLOAD:
            {
                Xcp_Download();
                break;
            }
            #if (XCP_DOWNLOAD_NEXT== STD_ON)
            case XCP_CMD_DOWNLOAD_NEXT:
            {
                Xcp_DownloadNext();
                break;
            }
            #endif
            #if (XCP_DOWNLOAD_MAX== STD_ON)
            case XCP_CMD_DOWNLOAD_MAX:
            {
                Xcp_DownloadMax();
                break;
            }
            #endif
            #if (XCP_MODIFY_BITS== STD_ON)
            case XCP_CMD_MODIFY_BITS:
            {
                Xcp_ModifyBits();
                break;
            }
            #endif
            /* PAG */
            #if (XCP_PAG_SUPPORT == STD_ON)

            #if (XCP_SET_CAL_PAGE == STD_ON)
            case XCP_CMD_SET_CAL_PAGE:
            {
                Xcp_SetCalPage();
                break;
            }
            #endif

            #if (XCP_GET_CAL_PAGE == STD_ON)
            case XCP_CMD_GET_CAL_PAGE:
            {
                Xcp_GetCalPage();
                break;
            }
            #endif

            #endif /* (XCP_PAG_SUPPORT == STD_ON)Xcp_ActivPagNum */
            /* end of CAL */
            #endif

            /*
             * DAQ Commands
             */
            #if (XCP_PL_DAQ == (XCP_PL_DAQ & XCP_RESOURCE))
            case XCP_CMD_SET_DAQ_PTR:
            {
                Xcp_SetDaqPtr();
                break;
            }
            case XCP_CMD_WRITE_DAQ:
            {
                Xcp_WriteDaq();
                break;
            }
            case XCP_CMD_SET_DAQ_LIST_MODE:
            {
                Xcp_SetDaqListMode();
                break;
            }
            case XCP_CMD_START_STOP_DAQ_LIST:
            {
                Xcp_StartStopDaqList();
                break;
            }
            case XCP_CMD_START_STOP_SYNCH:
            {
                Xcp_StartStopSynch();
                break;
            }
            #if (XCP_DAQ_CONFIG_TYPE == XCP_DAQ_STATIC)
            case XCP_CMD_CLEAR_DAQ_LIST:
            {
                Xcp_ClearDaqList();
                break;
            }
            #if (XCP_GET_DAQ_LIST_INFO == STD_ON)
            case XCP_CMD_GET_DAQ_LIST_INFO:
            {
                Xcp_GetDaqListInfo();
                break;
            }
            #endif
            #else
            case XCP_CMD_FREE_DAQ:
            {
                Xcp_FreeDaq();
                break;
            }
            case XCP_CMD_ALLOC_DAQ:
            {
                Xcp_AllocDaq();
                break;
            }
            case XCP_CMD_ALLOC_ODT:
            {
                Xcp_AllocOdt();
                break;
            }
            case XCP_CMD_ALLOC_ODT_ENTRY:
            {
                Xcp_AllocOdtEntry();
                break;
            }
            #endif
            #if (XCP_GET_DAQ_LIST_MODE == STD_ON)
            case XCP_CMD_GET_DAQ_LIST_MODE:
            {
                Xcp_GetDaqListMode();
                break;
            }
            #endif
            #if (XCP_TIMESTAMP_TYPE != XCP_TS_NO_TS)
            #if (XCP_GET_DAQ_CLOCK == STD_ON)
            case XCP_CMD_GET_DAQ_CLOCK:
            {
                Xcp_GetDaqClock();
                break;
            }
            #endif
            #endif
            #if (XCP_READ_DAQ == STD_ON)
            case XCP_CMD_READ_DAQ:
            {
                Xcp_ReadDaq();
                break;
            }
            #endif
            #if (XCP_GET_DAQ_PROCESSOR_INFO == STD_ON)
            case XCP_CMD_GET_DAQ_PROCESSOR_INFO:
            {
                Xcp_GetDaqProcessorInfo();
                break;
            }
            #endif
            #if (XCP_GET_DAQ_RESOLUTION_INFO == STD_ON)
            case XCP_CMD_GET_DAQ_RESOLUTION_INFO:
            {
                Xcp_GetDaqResolutionInfo();
                break;
            }
            #endif
            #if (XCP_GET_DAQ_EVENT_INFO == STD_ON)
            case XCP_CMD_GET_DAQ_EVENT_INFO:
            {
                Xcp_GetDaqEventInfo();
                break;
            }
            #endif
            /*
             * End of DAQ
             */
            #endif /*(XCP_PL_DAQ == (XCP_PL_DAQ & XCP_RESOURCE))*/

            /*
             * PGM
             */
            #if (XCP_PL_PGM == (XCP_PL_PGM & XCP_RESOURCE))
            case XCP_CMD_PROGRAM_START:
            {
                Xcp_ProgramStart();
                break;
            }
            case XCP_CMD_PROGRAM_CLEAR:
            {
                Xcp_ProgramClear();
                break;
            }
            case XCP_CMD_PROGRAM:
            {
                Xcp_Program();
                break;
            }
            case XCP_CMD_PROGRAM_RESET:
            {
                Xcp_ProgramReset();
                break;
            }
            #if (XCP_GET_PGM_PROCESSOR_INFO == STD_ON)
            case XCP_CMD_GET_PGM_PROCESSOR_INFO:
            {
                Xcp_GetPgmProcessorInfo();
                break;
            }
            #endif
            #if (XCP_GET_SECTOR_INFO == STD_ON)
            case XCP_CMD_GET_SECTOR_INFO:
            {
                Xcp_GetSectorInfo();
                break;
            }
            #endif
            #if (XCP_PROGRAM_PREPARE == STD_ON)
            case XCP_CMD_PROGRAM_PREPARE:
            {
                Xcp_ProgramPrepare();
                break;
            }
            #endif
            #if (XCP_PROGRAM_FORMAT == STD_ON)
            case XCP_CMD_PROGRAM_FORMAT:
            {
                Xcp_ProgramFormat();
                break;
            }
            #endif
            #if (XCP_PROGRAM_NEXT == STD_ON)
            case XCP_CMD_PROGRAM_NEXT:
            {
                Xcp_ProgramNext();
                break;
            }
            #endif
            #if (XCP_PROGRAM_MAX == STD_ON)
            case XCP_CMD_PROGRAM_MAX:
            {
                Xcp_ProgramMax();
                break;
            }
            #endif
            #if (XCP_PROGRAM_VERIFY == STD_ON)
            case XCP_CMD_PROGRAM_VERIFY:
            {
                Xcp_ProgramVerify();
                break;
            }
            #endif
            /*
             * End of PGM
             */
            #endif /* (XCP_PL_PGM == (XCP_PL_PGM & XCP_RESOURCE)) */

            default:
            {
                Xcp_SetErrorCode(XCP_ERR_CMD_UNKNOWN);
                Xcp_RespLength = 0x02;
                Xcp_SendResp();
                break;
            }
        }
    }
    else if (XCP_USERDEFINE == Xcp_Status)
    {
        /* Do nothing Now if needed some upper-level test commands can be
         * located here.
         */
        Xcp_CommandStatus = XCP_CMD_IDLE;
    }
    else
    {
        Xcp_CommandStatus = XCP_CMD_IDLE;
    }
    return;

}


FUNC(Std_ReturnType,XCP_CODE)
Xcp_Transmit (PduIdType pduId, PduLengthType len, P2VAR(uint8,AUTOMATIC,XCP_VAR) dataPtr)
{
    PduInfoType pduInfo;

    #if (XCP_ON_CAN_ENABLE == STD_ON)
    /* set length */
    #if (XCP_CAN_MAX_DLC_REQUIRED == STD_ON)
    pduInfo.SduLength = XCP_CAN_MAX_DLC;
    #else
    pduInfo.SduLength = len;
    #endif /* XCP_CAN_MAX_DLC == STD_ON */
    /* set data ptr */
    pduInfo.SduDataPtr = dataPtr;
    /* call API and return the result */
    return CanIf_Transmit(pduId, &pduInfo);

    #else
    return E_NOT_OK;
    #endif
}

/******************************************************************************/
/**
 * @brief               <Put a long into a byte array>
 *
 *      <This Function split the long type data to the byte type array>
 *
 * @param[in]           <u4Data         source long data>
 *                      <byteOrder>
 * @param[out]          <None>
 * @param[in/out]       <pu1BufferPtr   pointer to the byute array>
 * @return              <None>
 */
/******************************************************************************/
FUNC(void,XCP_CODE)
Xcp_CopyU4ToU1Buffer(const uint32 u4Data,
    P2VAR(uint8,AUTOMATIC,XCP_VAR) pu1BufferPtr, uint8 byteOrder)
{
    /*in case of Motorola MSB first*/
    if (HIGH_BYTE_FIRST == byteOrder)
    {
        pu1BufferPtr[0] = (uint8)(((u4Data)>>24) & 0xff);
        pu1BufferPtr[1] = (uint8)(((u4Data)>>16) & 0xff);
        pu1BufferPtr[2] = (uint8)(((u4Data)>>8) & 0xff);
        pu1BufferPtr[3] = (uint8)(((u4Data)>>0) & 0xff);
    }
    /*in case of Intel MSB last*/
    else
    {
        pu1BufferPtr[3] = (uint8)(((u4Data)>>24) & 0xff);
        pu1BufferPtr[2] = (uint8)(((u4Data)>>16) & 0xff);
        pu1BufferPtr[1] = (uint8)(((u4Data)>>8) & 0xff);
        pu1BufferPtr[0] = (uint8)(((u4Data)>>0) & 0xff);
    }
    return;
}

/******************************************************************************/
/**
 * @brief               <Put a word into a byte array>
 *
 *      <This Function split the long type data to the byte type array>
 *
 * @param[in]           <u2Data         source word data>
 *                      <byteOrder>
 * @param[out]          <None>
 * @param[in/out]       <pu1BufferPtr   pointer to the byute array>
 * @return              <None>
 */
/******************************************************************************/
FUNC(void,XCP_CODE)
Xcp_CopyU2ToU1Buffer(const uint16 u2Data,
                 P2VAR(uint8,AUTOMATIC,XCP_VAR) pu1BufferPtr, uint8 byteOrder)
{
    /*in case of Motorola MSB first*/
    if (HIGH_BYTE_FIRST == byteOrder)
    {
        pu1BufferPtr[0] = (uint8)(((u2Data)>>8) & 0xff);
        pu1BufferPtr[1] = (uint8)(((u2Data)>>0) & 0xff);
    }
    /*in case of Intel MSB last*/
    else
    {
        pu1BufferPtr[1] = (uint8)(((u2Data)>>8) & 0xff);
        pu1BufferPtr[0] = (uint8)(((u2Data)>>0) & 0xff);
    }
    return;
}

/******************************************************************************/
/**
 * @brief               <Put a byte array into a long>
 *
 *      <This Function split the byte type array to the long type data>
 *
 * @param[in]           <pu1BufferPtr   pointer to the byte array>
 *                      <byteOrder>
 * @param[out]          <None>
 * @param[in/out]       <pu4Data        pointer to the long>
 * @return              <None>
 */
/******************************************************************************/
FUNC(void,XCP_CODE)
Xcp_CopyU1BufferToU4(P2CONST(uint8,AUTOMATIC,XCP_VAR) pu1BufferPtr,
                              P2VAR(uint32,AUTOMATIC,XCP_VAR) pu4Data, uint8 byteOrder)
{
    /*in case of Motorola MSB first*/
    if (HIGH_BYTE_FIRST == byteOrder)
    {
        *pu4Data = ((uint32)pu1BufferPtr[0]<<24)
                 + ((uint32)pu1BufferPtr[1]<<16)
                 + ((uint32)pu1BufferPtr[2]<<8)
                 + ((uint32)pu1BufferPtr[3]<<0);
    }
    /*in case of Intel MSB last*/
    else
    {
        *pu4Data = ((uint32)pu1BufferPtr[3]<<24)
                 + ((uint32)pu1BufferPtr[2]<<16)
                 + ((uint32)pu1BufferPtr[1]<<8)
                 + ((uint32)pu1BufferPtr[0]<<0);
    }
    return;
}

/******************************************************************************/
/**
 * @brief               <Put a byte array into a word>
 *
 *      <This Function split the byte type array to the word type data>
 *
 * @param[in]           <pu1BufferPtr   pointer to the byte array>
 *                      <byteOrder>
 * @param[out]          <None>
 * @param[in/out]       <pu2Data        pointer to the word>
 * @return              <None>
 */
/******************************************************************************/
FUNC(void,XCP_CODE)
Xcp_CopyU1BufferToU2(P2CONST(uint8,AUTOMATIC,XCP_VAR) pu1BufferPtr,
                              P2VAR(uint16,AUTOMATIC,XCP_VAR) pu2Data, uint8 byteOrder)
{
    /*in case of Motorola MSB first*/
    if (HIGH_BYTE_FIRST == byteOrder)
    {
        *pu2Data = ((uint16)pu1BufferPtr[0]<<8)
                 + (uint16)pu1BufferPtr[1];

    }
    /*in case of Intel MSB last*/
    else
    {
        *pu2Data = ((uint16)pu1BufferPtr[1]<<8)
                 + (uint16)pu1BufferPtr[0];
    }
    return;
}

/******************************************************************************/
/**
 * @brief               <Copy Memory>
 *
 *      <This Function copy the data from source address to the destination address>
 *
 * @param[in]           <u4SourceAddr   source address
                         u4DestAddr     destination address
                         u4Length       memory length>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
FUNC(void,XCP_CODE) Xcp_CalBufferCopy(uint32 u4SourceAddr, uint32 u4DestAddr, uint32 u4Length)
{
    uint32 i;

    /*copy SourceAddr to DsetAddr*/
    for (i = 0u; i < u4Length; i++)
    {
        *(uint8*)(u4DestAddr + i) = *(uint8*)(u4SourceAddr + i);
    }
    return;
}

/******************************************************************************/
/**
 * @brief               <Set ErrorCode of the CRM>
 *
 *      <This Function set the error and the error PID>
 *
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Not Reentrant>
 * @param[in]           <u1ErrorCode    Error Code>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
FUNC(void,XCP_CODE)
Xcp_SetErrorCode(uint8 u1ErrorCode)
{
    /*set the Errorcode in the CRM buffer*/
    Xcp_RespBuffer[XCP_PID_OFFSET] = XCP_RESP_ERR_PID;
    Xcp_RespBuffer[XCP_RESP_ERROR_OFFSET] = u1ErrorCode;
    return;
}
/******************************************************************************/
/**
 * @brief               <Send a command response.>
 *
 * <Send a command response> .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
FUNC(void, XCP_CODE)
Xcp_SendResp(void)
{
	#if (XCP_SLAVE_BLOCK_MODE == STD_ON)
	uint8 pos;
	uint8 len;
	Xcp_AGType* destPtr;
	Xcp_AGType* sourPtr;
	#endif

	Xcp_SendStatus |= XCP_RESP_REQUEST;

	#if (XCP_BUS_TX_POLLING_MODE == STD_OFF)
	if (XCP_RESP_PENDING != (XCP_RESP_PENDING & Xcp_SendStatus))
	#endif
	{
		/* Block transfer mode */
		#if (XCP_SLAVE_BLOCK_MODE == STD_ON)
		if ((XCP_CMD_BLOCK_TRANSF == Xcp_CommandStatus)
		&& (Xcp_BlockBufferPos != Xcp_BlockBufferLen))
		{
			#if (XCP_BUS_TX_POLLING_MODE == STD_ON)
			do
			{
			#endif
				/* Set pointer */
				sourPtr = (Xcp_AGType*)Xcp_Mta2Ptr(Xcp_MTA.extensionAddr, Xcp_MTA.transferAddr);
				destPtr = (Xcp_AGType*)(&Xcp_RespBuffer[XCP_UPLOAD_DATA_OFFSET]);
				/* Get data length */
				len = (XCP_MAX_CTO / XCP_AG) - 1;
				if (len > (Xcp_BlockBufferLen - Xcp_BlockBufferPos))
				{
					len = Xcp_BlockBufferLen - Xcp_BlockBufferPos;
				}
				/* copy data into frame buffer */
				for (pos = 0; pos < len; pos++)
				{
					destPtr[pos] = sourPtr[pos];
				}
				/* Set frame length */
				Xcp_RespLength = (uint16)((len * XCP_AG) + XCP_UPLOAD_DATA_OFFSET);

				if (E_OK == Xcp_Transmit
					(Xcp_PBConfig.XcpPduRef->XcpTxPdu->LowLayerTxPduId, Xcp_RespLength, &Xcp_RespBuffer[0]))
				{
					/* updata buffer status */
					Xcp_SendStatus |= XCP_RESP_PENDING;
					Xcp_TransferTimeOutCnt = 0;
					Xcp_BlockBufferPos += len;
					Xcp_UpdateMTA(len * XCP_AG);
				}
			#if (XCP_BUS_TX_POLLING_MODE == STD_ON)
				else
				{
					/* in polling mode continuously send the frame until CAN buffer is full */
					break;
				}
				/* or until all data has been sent */
			}while (Xcp_BlockBufferPos != Xcp_BlockBufferLen);
			#endif /* (XCP_BUS_TX_POLLING_MODE == STD_ON) */
			/* block upload command has been sent */
			if (Xcp_BlockBufferPos == Xcp_BlockBufferLen)
			{
				Xcp_SendStatus &= (uint8)(~XCP_RESP_REQUEST);
				#if (XCP_BUS_TX_POLLING_MODE == STD_OFF)
				Xcp_CommandStatus = XCP_CMD_TRANSF;
				#else
				/*
				 * in polling mode we do not wait for txConfirmation
				 * thus, the command status shall goto idle immediately
				 */
				Xcp_CommandStatus = XCP_CMD_IDLE;
				#endif
			}
			/* if not in polling mode the time cost by the block transfer shall be
			 * take care when calculate the timeout threshold T1
			 */
			#if (XCP_BUS_TX_POLLING_MODE == STD_ON)
			else
			{
				/* in polling mode we may need a ev_cmd_pending
				 * when can't finish send all frame here
				 */
				Xcp_EvBuffer[XCP_PID_OFFSET] = XCP_EV_PID;
				Xcp_EvBuffer[XCP_EV_CODE_OFFEST] = XCP_EV_CMD_PENDING;
				Xcp_EvLength = 0x02;
				Xcp_SendEv();
			}
			#endif /* (XCP_BUS_TX_POLLING_MODE == STD_ON) */
		}
		else
		#endif /* XCP_SLAVE_BLOCK_MODE == STD_ON */
		/* Standard transfer mode */
		if (E_OK == Xcp_Transmit
			(Xcp_PBConfig.XcpPduRef->XcpTxPdu->LowLayerTxPduId, Xcp_RespLength, &Xcp_RespBuffer[0]))
		{
			Xcp_SendStatus &= (uint8)(~XCP_RESP_REQUEST);
			Xcp_SendStatus |= XCP_RESP_PENDING;
			Xcp_TransferTimeOutCnt = 0;
			{
				#if (XCP_BUS_TX_POLLING_MODE == STD_OFF)
				Xcp_CommandStatus = XCP_CMD_TRANSF;
				#else
				/*
				 * in polling mode we do not wait for txConfirmation
				 * thus, the command status shall goto idle immediately
				 */
				Xcp_CommandStatus = XCP_CMD_IDLE;
				/*
				 * In polling mode we do not wait for the txconfirmation
				 */
				if (XCP_PRE_CONNECT == Xcp_Status)
				{
					Xcp_Status = XCP_CONNECT;
				}
				else if (XCP_PRE_USERDEFINE == Xcp_Status)
				{
					Xcp_Status = XCP_USERDEFINE;
				}
				#endif
			}
		}
		else
		{
			/* Do Nothing */
		}
	}
	return;
}
/******************************************************************************/
/**
 * @brief               <Send a Event frame.>
 *
 * <Send a Event frame> .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
FUNC(void, XCP_CODE) Xcp_SendEv(void)
{

	Xcp_SendStatus |= XCP_EV_REQUEST;
    #if (XCP_BUS_TX_POLLING_MODE == STD_OFF)
    if (XCP_EV_PENDING != (XCP_EV_PENDING & Xcp_SendStatus))
    #endif
    {
        if (E_OK == Xcp_Transmit(Xcp_PBConfig.XcpPduRef->XcpTxPdu->LowLayerTxPduId, Xcp_EvLength, &Xcp_EvBuffer[0]))
        {
            Xcp_SendStatus &= (uint8)(~XCP_EV_REQUEST);
            Xcp_SendStatus |= XCP_EV_PENDING;
            Xcp_TransferTimeOutCnt = 0;
        }
    }

    return;
}

/******************************************************************************/
/**
 * @brief               <Send a Service frame.>
 *
 * <Send a Service frame>.
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
static FUNC(void, XCP_CODE) Xcp_SendServ(void)
{
    Xcp_SendStatus |= XCP_SERV_REQUEST;
    #if (XCP_BUS_TX_POLLING_MODE == STD_OFF)
    if (XCP_SERV_PENDING != (XCP_SERV_PENDING & Xcp_SendStatus))
    #endif
    {
        if (E_OK == Xcp_Transmit(Xcp_PBConfig.XcpPduRef->XcpTxPdu->LowLayerTxPduId,Xcp_ServLength, &Xcp_ServBuffer[0]))
        {
            Xcp_SendStatus &= (uint8)(~XCP_SERV_REQUEST);
            Xcp_SendStatus |= XCP_SERV_PENDING;
            Xcp_TransferTimeOutCnt = 0;
        }
    }
    return;
}
#define XCP_STOP_SEC_CODE
#include "XCP_MemMap.h"

#define XCP_START_SEC_CANIFRXINDICATION_CODE
#include "XCP_MemMap.h"
FUNC(void, XCP_CANIFRXINDICATION_CODE)
Xcp_CanIfRxIndication(
	PduIdType XcpRxPduId,
	P2CONST(PduInfoType,AUTOMATIC,XCP_APPL_DATA) XcpRxPduPtr
)
{
	#if (XCP_DEV_ERROR_DETECT == STD_ON)
	boolean errorFlag = FALSE;
	boolean pduIdError = FALSE;
	if (XCP_UINIT == Xcp_Status)
	{
		Det_ReportError(XCP_MODULE_ID, XCP_INSTANCE_ID, XCP_SERVICE_ID_RXINDICATION, XCP_E_NOT_INITIALIZED);
		errorFlag = TRUE;
	}
	else if (NULL_PTR == XcpRxPduPtr)
	{
		Det_ReportError(XCP_MODULE_ID, XCP_INSTANCE_ID, XCP_SERVICE_ID_RXINDICATION, XCP_E_INV_POINTER);
		errorFlag = TRUE;
	}
	else
	{
		if(Xcp_PBConfig.numOfRxPdu <= XcpRxPduId)
		{
			pduIdError = TRUE;
		}
		if (TRUE == pduIdError)
		{
			/* PduId check failed */
			Det_ReportError(XCP_MODULE_ID, XCP_INSTANCE_ID, XCP_SERVICE_ID_RXINDICATION, XCP_E_INVALID_PDUID);
			errorFlag = TRUE;
		}
	}
	if (TRUE != errorFlag)
	#endif /* XCP_DEV_ERROR_DETECT == STD_ON */
	{
		#if (XCP_CAN_MAX_DLC_REQUIRED == STD_ON)
		if (XCP_CAN_MAX_DLC == XcpRxPduPtr->SduLength)
		#endif
		{
			/* for CAN there is no header or tail that shall be removed
			 * so call the Xcp_RxIndication() directly
			 */
			#if (XCP_PID_OFF_SUPPORT  == STD_ON)
			Xcp_RxIndication(XcpRxPduId,XcpRxPduPtr->SduLength, XcpRxPduPtr->SduDataPtr);
			#else
			Xcp_RxIndication(XcpRxPduPtr->SduLength, XcpRxPduPtr->SduDataPtr);
			#endif
		}
	}
	return;
}
#define XCP_STOP_SEC_CANIFRXINDICATION_CODE
#include "XCP_MemMap.h"

#define XCP_START_SEC_CANIFTXINDICATION_CODE
#include "XCP_MemMap.h"
FUNC(void, XCP_CANIFTXINDICATION_CODE)
Xcp_CanIfTxConfirmation(
	PduIdType XcpTxPduId
)
{
	#if (XCP_DEV_ERROR_DETECT == STD_ON)
	if (XCP_UINIT == Xcp_Status)
	{
		Det_ReportError(XCP_MODULE_ID, XCP_INSTANCE_ID, XCP_SERVICE_ID_TXCONFIRMATION, XCP_E_NOT_INITIALIZED);
	}
	else
	#endif /* (XCP_DEV_ERROR_DETECT == STD_ON) */
	{
		Xcp_TxConfirmation(XcpTxPduId);
	}
	return;
}
#define XCP_STOP_SEC_CANIFTXINDICATION_CODE
#include "XCP_MemMap.h"

/******************************************************************************/
/*
 * @brief               <Xcp Module RxIndication Function>
 *
 * <This function will call associated handler to treat a STIM frame or a command
 * frame>.
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <len, dataPtr, pduId(in case PID_OFF supported)>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
static FUNC(void,XCP_CODE)
#if (XCP_PID_OFF_SUPPORT  == STD_ON)
Xcp_RxIndication
(const PduIdType pduId,const PduLengthType len, P2CONST(uint8, AUTOMATIC, XCP_APPL_DATA) dataPtr)
#else
Xcp_RxIndication
(const PduLengthType len, P2CONST(uint8, AUTOMATIC, XCP_APPL_DATA) dataPtr)
#endif
{
    uint8 pid = dataPtr[XCP_PID_OFFSET];
    /* STIM is not currently supported */

    /* A command has been received */
    if (len <= sizeof(Xcp_CmdBuffer))
    {
#if (XCP_PL_STIM == (XCP_PL_STIM & XCP_RESOURCE))
		if(XCP_CMD_CODE_MIN > pid)
		{
			/* Receive STIM,Cache into buffer */
			/* Not testing */
			Xcp_RxStimHal(len,dataPtr);
		}
		else
		{
#endif
			/* idle or synch command */
			if ((XCP_CMD_IDLE == Xcp_CommandStatus)
			|| (XCP_CMD_SYNCH == pid))
			{
				#if (XCP_MASTER_BLOCK_MODE == STD_ON)
				Xcp_RxCommandHal(pid, len, dataPtr);
				#else
				Xcp_RxCommandHal(len, dataPtr);
				#endif
			}
			else
			#if (XCP_MASTER_BLOCK_MODE == STD_ON)
			/* Block Recv */
			if (XCP_CMD_BLOCK_RECV == Xcp_CommandStatus)
			{
				Xcp_RxBlockHal(pid, len, dataPtr);
			}
			else
			#endif /* (XCP_MASTER_BLOCK_MODE == STD_ON) */
			/* cmd busy */
			{
				Xcp_SetErrorCode(XCP_ERR_CMD_BUSY);
				Xcp_RespLength = 0x02u;
				Xcp_SendResp();
			}
#if (XCP_PL_STIM == (XCP_PL_STIM & XCP_RESOURCE))
		}
#endif
    }
    else
    {
        /* Do Nothing */
    }
    return;
}

/******************************************************************************/
/*
 * @brief               <Xcp Module Command Rx Handeler>
 *
 * <This function copy command frame data into asosciated buffer>.
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <len, dataPtr, pid(in case Master_Block supported)>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
static FUNC(void,XCP_CODE)
#if (XCP_MASTER_BLOCK_MODE == STD_ON)
Xcp_RxCommandHal
(const uint8 pid, const PduLengthType len, P2CONST(uint8, AUTOMATIC, XCP_APPL_DATA) dataPtr)
#else
Xcp_RxCommandHal
(const PduLengthType len, P2CONST(uint8, AUTOMATIC, XCP_APPL_DATA) dataPtr)
#endif
{
    #if (XCP_MASTER_BLOCK_MODE == STD_ON)
    const Xcp_AGType* sourPtr;
    Xcp_AGType* destPtr;
    #endif
    uint16 lenCounter;
    #if (XCP_MASTER_BLOCK_MODE == STD_ON)
    Xcp_BlockBufIndxType pos;
    #endif

    #if (XCP_TIMESTAMP_TYPE != XCP_TS_NO_TS)
    #if (XCP_GET_DAQ_CLOCK == STD_ON)
    /* Get Recieve Time */
    (void) GetCounterValue(XCP_OS_COUNTER_ID, &Xcp_RxTimeStamp);
    #endif
    #endif

    /* copy data to the local buffer */
    for (lenCounter = 0; lenCounter < len; lenCounter++)
    {
        Xcp_CmdBuffer[lenCounter] = dataPtr[lenCounter];
    }
    Xcp_CmdLength = len;

    /*
     * Change Command Status
     */
    #if (XCP_MASTER_BLOCK_MODE == STD_ON)
    /*
     * Block Commands
     */
    if ((XCP_CMD_DOWNLOAD_NEXT == pid)
    || (XCP_CMD_PROGRAM_NEXT == pid))
    {
        Xcp_CommandStatus = XCP_CMD_EXCUTE;
        Xcp_SetErrorCode(XCP_ERR_SEQUENCE);
        Xcp_RespLength = 0x02u;
        Xcp_SendResp();
    }
    else
    #if (XCP_PL_CAL == (XCP_PL_CAL & XCP_RESOURCE))
    if ((XCP_CMD_DOWNLOAD == pid)
    && (dataPtr[XCP_DOWNLOAD_LEN_OFFSET] > XCP_DOWNLOAD_SIZE))
    {
        /* the length of the *_next shall be check here to prevent the overload
         * of the BlockBuffer
         */
        if (dataPtr[XCP_DOWNLOAD_LEN_OFFSET] <= XCP_DOWNLOAD_NEXT_SIZE)
        {
            /* get total length */
            Xcp_BlockBufferLen = dataPtr[XCP_DOWNLOAD_LEN_OFFSET];
            /* set pointer to the sour and dest [AG] */
            sourPtr = (const Xcp_AGType*)&dataPtr[XCP_DOWNLOAD_DATA_OFFSET];
            destPtr = &Xcp_BlockBuffer[0];
            /* copy data until the end of the frame */
            lenCounter = (XCP_DOWNLOAD_DATA_OFFSET + XCP_AG);
            for (pos = 0;
                 lenCounter <= len;
                 pos++)
            {
                destPtr[pos] = sourPtr[pos];
                lenCounter += XCP_AG;
            }
            /* updata some state and set the pid to download_next */
            Xcp_BlockBufferPos = pos;
            Xcp_CmdBuffer[XCP_PID_OFFSET] = XCP_CMD_DOWNLOAD_NEXT;
            Xcp_CommandStatus = XCP_CMD_BLOCK_RECV;
        }
        /* block length out of range */
        else
        {
            Xcp_CommandStatus = XCP_CMD_EXCUTE;
            Xcp_SetErrorCode(XCP_ERR_OUT_OF_RANGE);
            Xcp_RespLength = 0x02u;
            Xcp_SendResp();
        }
    }
    else
    #endif /* (XCP_PL_CAL == XCP_PL_CAL & XCP_RESOURCE) */
    #if (XCP_PL_PGM == (XCP_PL_PGM & XCP_RESOURCE))
    if ((XCP_CMD_PROGRAM == pid)
    && (dataPtr[XCP_PROGRAM_LEN_OFFSET] > XCP_PROGRAM_SIZE))
    {
        /* the length of the *_next shall be check here to prevent the overload
         * of the BlockBuffer
         */
        if (dataPtr[XCP_PROGRAM_LEN_OFFSET] <= XCP_PROGRAM_NEXT_SIZE)
        {
            /* get total length */
            Xcp_BlockBufferLen = dataPtr[XCP_PROGRAM_LEN_OFFSET];
            /* set pointer to the sour and dest [AG] */
            sourPtr = (const Xcp_AGType*)&dataPtr[XCP_PROGRAM_DATA_OFFSET];
            destPtr = &Xcp_BlockBuffer[0];
            /* copy data until the end of the frame */
            lenCounter = (XCP_PROGRAM_DATA_OFFSET + XCP_AG);
            for (pos = 0;
                 lenCounter <= len;
                 pos++)
            {
                destPtr[pos] = sourPtr[pos];
                lenCounter += XCP_AG;
            }
            /* updata some state and set the pid to download_next */
            Xcp_BlockBufferPos = pos;
            Xcp_CmdBuffer[XCP_PID_OFFSET] = XCP_CMD_PROGRAM_NEXT;
            Xcp_CommandStatus = XCP_CMD_BLOCK_RECV;
        }
        /* block length out of range */
        else
        {
            Xcp_CommandStatus = XCP_CMD_EXCUTE;
            Xcp_SetErrorCode(XCP_ERR_OUT_OF_RANGE);
            Xcp_RespLength = 0x02u;
            Xcp_SendResp();
        }
    }
    else
    #endif /* (XCP_PL_PGM == (XCP_PL_PGM & XCP_RESOURCE)) */
    #endif /* (XCP_MASTER_BLOCK_MODE == STD_ON) */
    /*
     * Non-Block Commands
     */
    {
        Xcp_CommandStatus = XCP_CMD_RECV;
    }
    return;
}

/******************************************************************************/
/*
 * @brief               <Xcp Module Rx Block Handeler>
 *
 * <This function will check and copy the data into the buffer in block transfer mode>.
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <len, dataPtr, pid>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
#if (XCP_MASTER_BLOCK_MODE == STD_ON)
static FUNC(void, XCP_CODE)
Xcp_RxBlockHal(const uint8 pid, const PduLengthType len,P2CONST(uint8, AUTOMATIC, XCP_APPL_DATA) dataPtr)
{
    const Xcp_AGType* sourPtr;
    Xcp_AGType* destPtr;
    uint16 lenCounter;
    uint16 lenMax = len;
    Xcp_BlockBufIndxType pos;

    /* pid shall be the associated *_NEXT */
    if (pid == Xcp_CmdBuffer[XCP_PID_OFFSET])
    {
        #if (XCP_PL_CAL == (XCP_PL_CAL & XCP_RESOURCE))
        if ((XCP_CMD_DOWNLOAD_NEXT == pid)
        && (dataPtr[XCP_DOWNLOAD_LEN_OFFSET] == (Xcp_BlockBufferLen - Xcp_BlockBufferPos))) /* Determine whether the length is consistent */
        {
            sourPtr = (const Xcp_AGType*)&dataPtr[XCP_DOWNLOAD_DATA_OFFSET];
            destPtr = &Xcp_BlockBuffer[Xcp_BlockBufferPos];
            lenCounter = XCP_DOWNLOAD_DATA_OFFSET + (uint16)(XCP_AG * (Xcp_BlockBufferLen - Xcp_BlockBufferPos));
            if (lenMax > lenCounter)
            {
                lenMax = lenCounter;
            }
            lenCounter = XCP_DOWNLOAD_DATA_OFFSET + XCP_AG;
            for (pos = 0; lenCounter <= lenMax; pos++)
            {
                destPtr[pos] = sourPtr[pos];
                lenCounter += XCP_AG;
            }
            Xcp_BlockBufferPos += pos;
            if (Xcp_BlockBufferPos == Xcp_BlockBufferLen)
            {
                Xcp_CommandStatus = XCP_CMD_RECV;
            }
        }
        else
        #endif
        #if (XCP_PL_PGM == (XCP_PL_PGM & XCP_RESOURCE))
        if ((XCP_CMD_PROGRAM_NEXT == pid)
        && (dataPtr[XCP_PROGRAM_LEN_OFFSET] == (Xcp_BlockBufferLen - Xcp_BlockBufferPos)))
        {
            sourPtr = (const Xcp_AGType*)&dataPtr[XCP_PROGRAM_DATA_OFFSET];
            destPtr = &Xcp_BlockBuffer[Xcp_BlockBufferPos];
            lenCounter = XCP_PROGRAM_DATA_OFFSET + (uint16)(XCP_AG * (Xcp_BlockBufferLen - Xcp_BlockBufferPos));
            if (lenMax > lenCounter)
            {
                lenMax = (uint16)lenCounter;
            }
            lenCounter = XCP_PROGRAM_DATA_OFFSET + XCP_AG;
            for (pos = 0; lenCounter <= lenMax; pos++)
            {
                destPtr[pos] = sourPtr[pos];
                lenCounter += XCP_AG;
            }
            Xcp_BlockBufferPos += pos;
            if (Xcp_BlockBufferPos == Xcp_BlockBufferLen)
            {
                Xcp_CommandStatus = XCP_CMD_RECV;
            }
        }
        /* Usually this branch is useless. */
        else
        #endif
        {
            Xcp_CommandStatus = XCP_CMD_EXCUTE;
            Xcp_SetErrorCode(XCP_ERR_SEQUENCE);
            Xcp_RespBuffer[XCP_RESP_ERROR_OFFSET+1] = Xcp_BlockBufferLen - Xcp_BlockBufferPos;
            Xcp_RespLength = 0x03u;
            Xcp_SendResp();
        }
    }
    /* with wrong pid in the sequence an error shall be reported */
    else
    {
        Xcp_CommandStatus = XCP_CMD_EXCUTE;
        Xcp_SetErrorCode(XCP_ERR_SEQUENCE);
        Xcp_RespLength = 0x02u;
        Xcp_SendResp();
    }
    return;
}
#endif /* (XCP_MASTER_BLOCK_MODE == STD_ON) */


/******************************************************************************/
/**
 * @brief               <Xcp module transmission confirmation>
 *
 * <It update the flag and try to send next frame if there is one when last frame
 *  has been reported sent successfully> .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Not Reentrant>
 * @param[in]           <pduId: PduId of last DTO/CTO>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
static FUNC(void, XCP_CODE) Xcp_TxConfirmation(const PduIdType pduId)
{
    /* Since last frame has been sent, clear the pending flag */
    Xcp_SendStatus &= (uint8)(~XCP_SEND_PENDING);
    Xcp_TransferTimeOutCnt = 0x00u;

    /* In case the bus driver is working in polling mode the commandstatus
     * will be set to Idle immediately when the <lower_layer>_Transmit is return E_OK
     */
    #if (XCP_BUS_TX_POLLING_MODE == STD_OFF)
    /* in case interrupt mode is used, we change status here, otherwise
     * this shall be done in Xcp_SendResp()
     */
    /* After the CRM sent, reset the command status */
    if ((XCP_CMD_TRANSF == Xcp_CommandStatus)
    && (pduId == Xcp_PBConfig.XcpPduRef->XcpTxPdu->XcpLocalTxPduId))
    {
        Xcp_CommandStatus = XCP_CMD_IDLE;
        /* stack will go into the connected status when the positive ack sent successfully */
        if (XCP_PRE_CONNECT == Xcp_Status)
        {
            Xcp_Status = XCP_CONNECT;
        }
        else if (XCP_PRE_USERDEFINE == Xcp_Status)
        {
            Xcp_Status = XCP_USERDEFINE;
        }
        else
        {
            /* do nothing */
        }
    }
    #endif /* XCP_BUS_TX_POLLING_MODE == STD_OFF */
    /* Send next frame if necessary */
    Xcp_TxQueueHandler();
    return;
}

static FUNC(void, XCP_CODE) Xcp_TxQueueHandler(void)
{
    if (XCP_RESP_REQUEST == (XCP_RESP_REQUEST & Xcp_SendStatus))
    {
        Xcp_SendResp();
    }
    if (XCP_SERV_REQUEST == (XCP_SERV_REQUEST & Xcp_SendStatus))
    {
        Xcp_SendServ();
    }
    if (XCP_EV_REQUEST == (XCP_EV_REQUEST & Xcp_SendStatus))
    {
        Xcp_SendEv();
    }
    /* here we put Daq below the Ev cause there is some Ev has high priority than DAQ
     * for example Ev_Sleep
     */
    #if (XCP_PL_DAQ == (XCP_PL_DAQ & XCP_RESOURCE))
    if (XCP_DAQ_REQUEST == (XCP_DAQ_REQUEST & Xcp_SendStatus))
    {
        Xcp_SendDaq();
    }
    #endif
    return;
}

